home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Essentials / MacApp Documentation / MacApp AppleLink Messages / MacApp.Tech$ 12⁄8⁄89 / 0180-RE Failure Handling -Dec89 < prev    next >
Encoding:
Text File  |  1989-12-08  |  6.9 KB  |  258 lines  |  [TEXT/GEOL]

  1. Item    3664185                         8-Dec-89        10:28
  2.  
  3. From:   MADA2                           MacApp Dev Assoc, Curtis Faith
  4.  
  5. To:     D1950                           CSG, Don Phillips,PRT
  6.  
  7. cc:     MACAPP.TECH$                    MacApp Technical
  8.  
  9. Sub:    RE: Failure Handling (long)
  10.  
  11. Jo-Anne,
  12.  
  13. Failure handling can be trickier than it looks.  In you example a lot depends
  14. on exactly what you are creating the objects for.  If you are later going to
  15. assign them to fields of TTObject4 then your handling can be simplified.
  16.  
  17. The issues as I see them are this:
  18.  
  19. 1) You can have 9 possible failures.
  20.     a) during each of the 3 creations (NEW's).
  21.     b) during each of the 3 TInitializations.
  22.     c) during each of the 3 { Do something that can fails }
  23.  
  24. 2) A failure in the first 2 areas for the first object needs no handler as the
  25. object will either never have been created in the case of FailNIL or it will be
  26. free automatically in the case of tmpObject1.IObject1.
  27.  
  28. 3) A failure after where you insert the first handler needs to free the first
  29. object. This and the above apply to all 3 objects.
  30.  
  31. 4) Since each object can have already been freed via the IObjectX method one
  32. need make allowances for non-NIL but already freed objects.  THIS IS WHAT
  33. REALLY COMPLICATES MATTERS.  For if an object could be guarranteed to be either
  34. valid and or NIL then you could have one handler:
  35.  
  36.        PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
  37.  
  38.        BEGIN
  39.        IF tmpObject1 <> NIL THEN
  40.            FreeIfObject(tmpObject1);
  41.        IF tmpObject2 <> NIL THEN
  42.            FreeIfObject(tmpObject2);
  43.        IF tmpObject3 <> NIL THEN
  44.            FreeIfObject(tmpObject3);
  45.        END;
  46.  
  47. and even the NIL tests in the above would be unnecessary as FreeIfObject tests
  48. for this already (I like to put them in for clarities sake).
  49.  
  50.  
  51. 5) None of the NIL assignments that you have appear to be necessary.  This is
  52. because there is no chance that any of the objects will be FreeIfObject'd until
  53. after they have been NEW'd, at which point they would either be set to NIL by
  54. NEW or be a valid reference.
  55.  
  56. There is another way to handle the above situation that might be preferable but
  57. it is still a little messy.  You could define 3 more local variables:
  58.  
  59. PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
  60.  
  61. VAR
  62.     aObject1: TObject1;
  63.     aObject2: TObject2;
  64.     aObject2: TObject2;
  65.     tmpObject1  : TTObject1;
  66.     tmpObject2  : TTObject2;
  67.     tmpObject3  : TTObject3;
  68.     fi          : FailInfo;
  69.  
  70.        PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
  71.  
  72.        BEGIN
  73.        IF aObject1 <> NIL THEN
  74.            FreeIfObject(aObject1);
  75.        IF aObject2 <> NIL THEN
  76.            FreeIfObject(aObject2);
  77.        IF aObject3 <> NIL THEN
  78.            FreeIfObject(aObject3);
  79.        END;
  80.  
  81. BEGIN
  82.     aObject1 := NIL;
  83.     aObject2 := NIL;
  84.     aObject3 := NIL;
  85.  
  86.     CatchFailures( fi, HandleFailure );
  87.  
  88.     New( tmpObject1 );
  89.     FailNIL( tmpObject1 );
  90.     tmpObject1.IObject1;
  91.     aObject1 := tmpObject1;
  92.  
  93.     { Do something that could fail 1. }
  94.  
  95.     New( tmpObject2 );
  96.     FailNIL( tmpObject2 );
  97.     tmpObject2.IObject2;
  98.     aObject2 := tmpObject2;
  99.  
  100.    { Do something that could fail 2. }
  101.  
  102.     New( tmpObject3 );
  103.     FailNIL( tmpObject3 );
  104.     tmpObject3.IObject3;
  105.     aObject3 := tmpObject3;
  106.  
  107.    { Do something that could fail 3. }
  108.  
  109.     Success( fi );
  110.  
  111. END;
  112.  
  113. Here we correctly handle a failure in any of the above 9 places and still have
  114. only one failure handler.  A Failure anywhere after an assignment aObjectX :=
  115. tmpObjectX will free aObjectX.
  116.  
  117. I believe that there would be less overhead involved in the storage of the 3
  118. new variables and their assignment than in using the 2 additional failure
  119. handlers that you listed.
  120.  
  121. A closely related example would be where one would want to assign each of the 3
  122. objects to a field of TObject4 and TObject4.Free freed each field if non-NIL.
  123.  
  124. PROCEDURE TTObject4.Free; OVERRIDE;
  125. BEGIN
  126.     IF aObject1 <> NIL THEN
  127.         FreeIfObject(aObject1);
  128.     IF aObject2 <> NIL THEN
  129.         FreeIfObject(aObject2);
  130.     IF aObject3 <> NIL THEN
  131.         FreeIfObject(aObject3);
  132.  
  133.     INHERITED Free;
  134. END;
  135.  
  136. PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
  137.  
  138. VAR
  139.     tmpObject1  : TTObject1;
  140.     tmpObject2  : TTObject2;
  141.     tmpObject3  : TTObject3;
  142.     fi          : FailInfo;
  143.  
  144.        PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
  145.  
  146.        BEGIN
  147.        Free;
  148.        END;
  149.  
  150. BEGIN
  151.     aObject1 := NIL;
  152.     aObject2 := NIL;
  153.     aObject3 := NIL;
  154.  
  155.     CatchFailures( fi, HandleFailure );
  156.  
  157.     New( tmpObject1 );
  158.     FailNIL( tmpObject1 );
  159.     tmpObject1.IObject1;
  160.     fObject1 := tmpObject1;
  161.  
  162.     { Do something that could fail 1. }
  163.  
  164.     New( tmpObject2 );
  165.     FailNIL( tmpObject2 );
  166.     tmpObject2.IObject2;
  167.     fObject2 := tmpObject2;
  168.  
  169.    { Do something that could fail 2. }
  170.  
  171.     New( tmpObject3 );
  172.     FailNIL( tmpObject3 );
  173.     tmpObject3.IObject3;
  174.     fObject3 := tmpObject3;
  175.  
  176.    { Do something that could fail 3. }
  177.  
  178.     Success( fi );
  179.  
  180. END;
  181.  
  182. One further variation that would complicate matters would be in the above case
  183. if each of the 3 objects did not free itself when failing in IOBjectX.
  184.  
  185. PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
  186.  
  187. VAR
  188.     tmpObject1  : TTObject1;
  189.     tmpObject2  : TTObject2;
  190.     tmpObject3  : TTObject3;
  191.     fi          : FailInfo;
  192.  
  193.        PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
  194.  
  195.        BEGIN
  196.        Free;
  197.        END;
  198.  
  199. BEGIN
  200.     aObject1 := NIL;
  201.     aObject2 := NIL;
  202.     aObject3 := NIL;
  203.  
  204.     CatchFailures( fi, HandleFailure );
  205.  
  206.     New( tmpObject1 );
  207.     FailNIL( tmpObject1 );
  208.     fObject1 := tmpObject1;
  209.     tmpObject1.IObject1;
  210.  
  211.     { Do something that could fail 1. }
  212.  
  213.     New( tmpObject2 );
  214.     FailNIL( tmpObject2 );
  215.     fObject2 := tmpObject2;
  216.     tmpObject2.IObject2;
  217.  
  218.    { Do something that could fail 2. }
  219.  
  220.     New( tmpObject3 );
  221.     FailNIL( tmpObject3 );
  222.     fObject3 := tmpObject3;
  223.     tmpObject3.IObject3;
  224.  
  225.    { Do something that could fail 3. }
  226.  
  227.     Success( fi );
  228.  
  229. END;
  230.  
  231. In this case merely moving the assignment of fObjectX := tmpObjectX up before
  232. the initialization will accomplish our goal, since after this assignment is
  233. made we can be sure that the newly created object will get Free'd when
  234. TObject4.Free is called from the "HandleFailure" failure handler.
  235.  
  236. In general one needs to examine things very closely when implementing these
  237. confusing failure handlers.  In particular it is important what the effects of
  238. a failure during the Initialization stage of an object are.  If an object will
  239. free itself one need make allowances for non-NIL but already freed objects.
  240.  
  241. In my opinion, additional temporary variables or fields that have been preset
  242. to NIL and are assigned just after the initialization method are preferable to
  243. having multiple failure handlers.
  244.  
  245. All this leads one to believe that automatic garbage collection would indeed be
  246. a valuable thing.  In that case failure handlers would be far less frequently
  247. necessary.
  248.  
  249. I hope I did not add to the confusion.
  250.  
  251. - Curtis
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.